import zmq
import threading
import time
import netifaces as ni #external
import cPickle
import json
import zlib
import sys
import signal
import logging
from collections import *
sys.path.append("./")
from random import choice
from utils import *

interrupted = False

def tree():return defaultdict(tree)

policy_store=[]

def signal_handler(signum, frame):
    global interrupted
    interrupted = True
signal.signal(signal.SIGINT, signal_handler)

class MSG(object):
    """docstring for MSG"""
    def __init__(self):
        pass
    def msg_reg_new(self,mid):
        msg={}
        msg["id"]=mid
        msg["type"]="guard_new"
        msg["body"]=get_host_info()
        return json.dumps(msg)

    def msg_req_in(self,mid,fid):
        msg={}
        msg["id"]=mid
        msg["from_id"]=fid
        msg["type"]="req_in"
        msg["body"]=get_host_info()
        return json.dumps(msg)
        

class PolicyGuard(threading.Thread):
    """docstring for PolicyGuard"""
    def __init__(self):
        threading.Thread.__init__ (self)
        self.id="None"
        self.context = zmq.Context()
        self.app_router = self.context.socket(zmq.ROUTER)
        self.app_dealer = self.context.socket(zmq.DEALER)
        self.ctr_router = self.context.socket(zmq.DEALER)
        self.ctr_dealer = self.context.socket(zmq.DEALER)
        self.app_list={}
        self.sockets=[]
        self.worker_no=10
        self.workers=[]
        self.st_time=0
        self.ed_time=0
        self.total_count=0
        self.miss_count=0
        
        
        self.msg=Message()
        self.poller = zmq.Poller()
        self.bind()
        self.register_clr()
        self.register_poll()
        self.init_worker()
        self.run()
        self.clean()


    def bind(self):
        self.app_router.bind('ipc://guard_app.ipc')
        self.app_dealer.bind('inproc://guard_worker.ipc')
        self.ctr_dealer.bind('inproc://guard_ctr.ipc')

    def clean(self):
        self.app_router.close()
        self.app_dealer.close()
        self.ctr_dealer.close()
        self.ctr_router.close()
        self.context.term()
    
    def register_poll(self):
        self.poller.register(self.app_router, zmq.POLLIN)
        self.poller.register(self.app_dealer,  zmq.POLLIN)
        self.poller.register(self.ctr_router,  zmq.POLLIN)
        self.poller.register(self.ctr_dealer,  zmq.POLLIN)
        

    def register_clr(self):
        self.ctr_router.connect('tcp://localhost:5555')
        self.ctr_router.send(self.msg.msg_reg_new(self.id))
        while 1:
            msg = self.ctr_router.recv()
            msg=eval(msg)
            if msg[MSG_TYPE]==TYPE_REP_REGISTER:
                self.id=msg[MSG_SENDER]
                print msg
                self.ctr_router.close()
                self.ctr_router = self.context.socket(zmq.DEALER)
                self.ctr_router.setsockopt(zmq.IDENTITY, self.id)
                self.ctr_router.connect('tcp://localhost:5555')
                break

    def init_worker(self):
        for i in xrange(self.worker_no):
            worker = ServerWorker(self.context,self.app_router)
            worker.start()
            self.workers.append(worker)

    def event_app_reg(self,appid):
        msg={}
        msg[MSG_SENDER]=self.id
        msg[MSG_TYPE]=TYPE_APP_ADD
        msg[MSG_BODY]=appid
        #self.ctr_router.send(self.id,zmq.SNDMORE)
        self.ctr_router.send(pack_msg(msg))
        t=self.ctr_router.recv()
        pass
    
    def run(self):
        self.st_time=time.time()
        while 1:
            sockets = dict(self.poller.poll(1))
            if self.app_router in sockets:
                if sockets[self.app_router] == zmq.POLLIN:
                    _id = self.app_router.recv()
                    msg = self.app_router.recv()
                    if _id not in self.app_list:
                        self.event_app_reg(_id)
                        self.app_list[_id]=1
                    self.total_count+=1
                    if self.total_count==100000:
                        self.ed_time=time.time()
                        print "time usage:",self.ed_time,self.st_time,self.ed_time-self.st_time
                        print "hit_count:",self.total_count-self.miss_count
                        print "miss_count:",self.miss_count
                        print "total count:",self.total_count
                        print "rate:",float(self.total_count)/float(self.ed_time-self.st_time)
                        sys.exit()
                    
                    #print 'guard received msg: %s from app %s' % (msg, _id)

                    """
                    app_registration()
                    """
                    self.app_dealer.send(_id, zmq.SNDMORE)
                    self.app_dealer.send(msg)
            if self.app_dealer in sockets:
                if sockets[self.app_dealer] == zmq.POLLIN:
                    _id = self.app_dealer.recv()
                    msg = self.app_dealer.recv()

                    self.app_router.send(_id, zmq.SNDMORE)
                    self.app_router.send(msg)

            if self.ctr_dealer in sockets:
                if sockets[self.ctr_dealer] == zmq.POLLIN:
                    _id = self.ctr_dealer.recv()
                    msg = self.ctr_dealer.recv(copy=False)
                    #print msg
                    #print 'guard dont know what to do for the request from %s' % (_id)
                    self.miss_count+=1
                    #self.ctr_router.send(_id, zmq.SNDMORE)
                    self.ctr_router.send(self.msg.msg_req_in(self.id,_id))
 

            if self.ctr_router in sockets:
                if sockets[self.ctr_router] == zmq.POLLIN:
                    msg = self.ctr_router.recv()
                    msg=eval(msg)
                    #print "recv msg"
                    #print msg["type"]
                    if msg["type"]=="test":
                        #print msg
                        pass
                    if msg["type"]=="control_rep":
                        #print msg["body"]
                        _id=msg["from_id"]
                        self.app_router.send(_id, zmq.SNDMORE)
                        self.app_router.send("ok, block it")
                    if msg[MSG_TYPE]==TYPE_POLICY_PUT:
                        rules=msg[MSG_BODY]["POLICY"]
                        for r in rules:
                            self.test(r)
        pass

    def test(self,r):
        print r
        policy_store.append(eval(r))
        """
    	the passed items are in a given order, or a hash_map
        """

        #generate a order, the last one must be the "Effect"

        #get items by the order

        #then build a tree,each level represent a item

        """	
     

        """

#logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S",level=logging.INFO, filename='test.log',filemode='a') 


class ServerWorker(threading.Thread):
    """ServerWorker"""
    def __init__(self,context,sender):
        threading.Thread.__init__ (self)
        self.context = context
        self.sender = sender
        #self.err_dealer=dealer
        #self.msg=MSG()

    def lazy_match(self,match):
        #print policy_store
        #print match
        for r in policy_store:
            flag=0
            for i in r.keys():
                if i=="PRINCIPLE" and i=="EFFECT":
                    continue
                if r[i]=="ANY":
                    continue
                if r[i]!=match[i]:
                    flag=1
                    break
            if flag==1:
                return "DENY"
            else:
                return r["EFFECT"]

    def run(self):
        worker = self.context.socket(zmq.DEALER)
        worker.connect('inproc://guard_worker.ipc')

        err_dealer = self.context.socket(zmq.DEALER)
        err_dealer.connect('inproc://guard_ctr.ipc')


        print 'worker started'
        while 1:
            _id = worker.recv()
            msg = worker.recv()
            #print 'worker received %s from %s' % (msg, _id)
            #logging.info("get message: %s", msg)
            #rep = str(time.time())[0:10]
            #if int(rep)%5==0:
                #err_dealer.send(_id,zmq.SNDMORE)
                #err_dealer.send(msg)
                #self.err_dealer.send(self.msg.msg_req_in(self.id,_id))
            #if 1:
            worker.send(_id, zmq.SNDMORE)
            worker.send(self.lazy_match(eval(msg)))

            del msg

        worker.close()

if __name__ == '__main__':
    guard = PolicyGuard()
    st_time=time.time()
    guard.start()
    ed_time=time.time()
    print "sys time usage",ed_time-st_time